package com.cskaoyan.javase.recursion._0introduction;

/**
 * @description: 递归的引入
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 回到Java语法当中，方法是可以调用方法的。
 * > ​	实际上，我们总是在main方法（程序入口方法）中调用其它方法，才能够去使用该方法
 * - 特别的，在一个方法当中再次调用这个方法，就像故事里提到同样的故事一样
 * - 我们把方法在运行时调用自身的情况，称之为递归，又叫做递归调用
 *
 * 使用递归的注意事项：
 *      1.使用递归必须存在自己调用自己的语句,称之为递归体
 *      2.仅有递归体的递归方法会无限制得递归导致栈溢出错误,如果想要递归正常执行
 *          必须明确指出递归在什么时候结束,称之为递归的出口
 *          停止递归指的是不再继续调用自身
 *      3.拥有递归体和递归出口的方法也不一定就是绝对安全的
 *          还需要考虑递归的次数,如果出口过于遥远,直到栈溢出都不能到达出口
 *          仍然会出问题
 *          递归的次数称之为递归的深度
 *      4.递归是很危险的,很容易导致栈溢出,所以使用它要格外小心,尽量不要用它
 *
 */
public class Demo {
    public static void main(String[] args) {
        System.out.println(sum(15000));
        /**
         * 分析程序:
         * sum(10) = 10 + sum(9);
         * sum(9) = 9 + sum(8);
         * sum(8) = 8 + sum(7);
         * ....
         * 显然以上过程是不能停下来的,所以请思考,代码的执行结果:
         * 1.死循环
         * 2.程序出错
         * 3.电脑炸了
         *
         * sum方法是我们自己写的java代码方法,它的调用需要占用JVM栈内存空间
         * 在方法调用时,方法只有调用结束了,方法的栈帧才会出栈
         * 这上面案例中,方法只会进栈不会出栈,终究会导致栈内存不够用,导致内存溢出,程序的执行就会报错
         * Method 'sum()' recurses infinitely, and can only end by throwing an exception
         * 无限制递归,程序只能通过抛出异常结束
         * 抛出的异常是StackOverflowError,栈溢出错误,Error是比Exception更加严重的问题
         *
         * 添加了递归出口 if (n == 0) return 0; 以后
         * sum(10) = 10 + sum(9);
         * sum(9) = 9 + sum(8);
         * sum(8) = 8 + sum(7);
         * ....
         * sum(1) = 1 + sum(0);
         * sum(0) = 0;
         * 结果就是10 + ... + 3 + 2 + 1 = 55
         *
         */

    }

    public static int sum(int n){
        //递归的出口,作为递归停止的条件
        if (n == 0) return 0;
        //递归当中方法必须调用自身
        return n + sum(n -1);
    }
}
